1 /** 2 The following example comes from 3 $(LINK http://thoughts.davisjeff.com/2010/09/25/exclusion-constraints-are-generalized-sql-unique/). 4 */ 5 module test.examples_exclusion_constraint; 6 7 version(D_Ddoc) 8 { 9 /// 10 class BlankClassSoDocsWillBeGenerated { } 11 } 12 13 /** 14 This example is for the EXCLUSION constraint in Postgresql. 15 I will do an example with overlapping date ranges. 16 The table in SQL can be created by 17 $(D $(D $(D sql 18 CREATE TABLE b 19 ( 20 id INTEGER NOT NULL PRIMARY KEY, 21 p PERIOD 22 ); 23 ALTER TABLE b ADD EXCLUDE USING gist (p WITH &&); 24 25 ))) 26 */ 27 unittest 28 { 29 import std.datetime; 30 31 import db_constraints; 32 33 struct Period 34 { 35 Date startDate; 36 Date endDate; 37 38 invariant 39 { 40 assert(startDate <= endDate); 41 } 42 43 bool overlapsWith(in Period i) 44 { 45 return (this.startDate <= i.endDate && i.startDate <= this.endDate); 46 } 47 } 48 49 @ExclusionConstraint!((a, b) => a.p.overlapsWith(b.p)) 50 class B 51 { 52 private int _id; 53 // marking id with not null and primary key 54 @NotNull @PrimaryKeyColumn 55 @property int id() 56 { 57 return _id; 58 } 59 @property void id(int value) 60 { 61 setter(_id, value); 62 } 63 64 private Period _p; 65 @property inout(Period) p() inout 66 { 67 return _p; 68 } 69 @property void p(Period value) 70 { 71 setter(_p, value); 72 } 73 74 this(int id_, Period p_) 75 { 76 this._id = id_; 77 this._p = p_; 78 // do not forget to initialize the keyed item! 79 initializeKeyedItem(); 80 } 81 82 // do not forget to add in the keyed item! 83 mixin KeyedItem!(); 84 } 85 86 alias Bs = BaseKeyedCollection!(B); 87 88 import std.exception : assertNotThrown, assertThrown; 89 90 auto bs = new Bs(); 91 92 auto first = Period(Date(2009, 01, 05), Date(2009, 01, 10)); 93 assertNotThrown!ExclusionConstraintException(bs.add(new B(1, first))); 94 auto second = Period(Date(2009, 01, 07), Date(2009, 01, 12)); 95 assert(first.overlapsWith(second)); 96 assertThrown!ExclusionConstraintException(bs.add(new B(2, second))); 97 auto third = Period(Date(2009, 01, 17), Date(2009, 01, 22)); 98 assert(!first.overlapsWith(third)); 99 assertNotThrown!ExclusionConstraintException(bs.add(new B(2, third)));}